package ru.alt22.visor.php.ui.providers;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.Comparator;

import org.eclipse.core.resources.IProject;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.jface.viewers.IStructuredContentProvider;
import org.eclipse.jface.viewers.Viewer;
import org.eclipse.php.internal.core.phpModel.IPHPLanguageModel;
import org.eclipse.php.internal.core.phpModel.parser.IPhpModel;
import org.eclipse.php.internal.core.phpModel.parser.PHPProjectModel;
import org.eclipse.php.internal.core.phpModel.parser.PHPWorkspaceModelManager;
import org.eclipse.php.internal.core.phpModel.phpElementData.CodeData;
import org.eclipse.php.internal.core.phpModel.phpElementData.PHPClassData;
import org.eclipse.php.internal.core.phpModel.phpElementData.PHPModifier;
import org.eclipse.php.internal.core.project.PHPNature;

import ru.alt22.visor.php.core.PDToolsCorePlugin;
import ru.alt22.visor.php.ui.utils.Acceptable;
import ru.alt22.visor.php.ui.utils.CompositeAcceptable;

abstract public class PHPElementContentProvider implements IStructuredContentProvider {
	final public static Acceptable CLASSES_FILTER = new Acceptable() {
		public boolean accept(Object element) {
			PHPClassData classData = (PHPClassData) element;
			if (PHPModifier.isInterface(classData.getModifiers())) {
				return false;
			}
			if (PHPModifier.isFinal(classData.getModifiers())) {
				return false;
			}
			return true;
		}
	}; 
	final public static Acceptable INTERFACES_FILTER = new Acceptable() {
		public boolean accept(Object element) {
			PHPClassData classData = (PHPClassData) element;
			if (!PHPModifier.isInterface(classData.getModifiers())) {
				return false;
			}
			return true;
		}
	};

	private IProject project;
	private CompositeAcceptable filter = new CompositeAcceptable();

	public void setProject(IProject project) {
		this.project = project;
	}

	public IProject getProject() {
		return project;
	}

	public void addFilter(Acceptable filter) {
		this.filter.add(filter);
	}

	public static PHPClassData[] getClasses() {
		return getPHPType(CLASSES_FILTER);
	}

	public static PHPClassData[] getInterfaces() {
		return getPHPType(INTERFACES_FILTER);
	}

	public Object[] getElements(Object inputElement) {
		return getPHPType(filter);
	}

	private static PHPClassData[] getPHPType(Acceptable filter) {
		//TODO Determine PHPLanguageModel from selection or active file
		ArrayList<PHPClassData> phpClassesList = new ArrayList<PHPClassData>();
		IProject[] projects = PDToolsCorePlugin.getWorkspace().getRoot().getProjects();

		boolean phpAdded = false;
		for (int i = 0; i < projects.length; i++) {
			IProject project = projects[i];
			try {
				if (!project.exists() || !project.isOpen() || !project.hasNature(PHPNature.ID)) {
					continue;
				}
			} catch (CoreException ce) {
				ce.printStackTrace();
				continue;
			}

			PHPProjectModel projectModel = PHPWorkspaceModelManager.getInstance().getModelForProject(project);
			IPhpModel[] models = projectModel.getModels();
			for (int j = 0; j < models.length; ++j) {
				IPhpModel model = models[j];

				if (model instanceof IPHPLanguageModel) {
					if (phpAdded) {
						continue;
					}
					phpAdded = true;
				}

				addToList(model.getClasses(), phpClassesList, filter);
			}
		}

		PHPClassData[] phpClasses = phpClassesList.toArray(new PHPClassData[phpClassesList.size()]);
		Arrays.sort(phpClasses, new Comparator<Object>() {
			public int compare(Object arg0, Object arg1) {
				return arg0.toString().compareToIgnoreCase(arg1.toString());
			}
		});
		return phpClasses;
	}

	private static void addToList(CodeData[] data, ArrayList<PHPClassData> arrayList, Acceptable filter) {
		for (int i = 0; i < data.length; i++) {
			PHPClassData classData = (PHPClassData) data[i];
			if (!filter.accept(classData)) {
				continue;
			}
			arrayList.add(classData);
		}
	}

	public void inputChanged(Viewer viewer, Object oldInput, Object newInput) {
	}

	public void dispose() {
	}

}